home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
FAQs
/
SGIfaqs
/
DSO-faq
next >
Wrap
Text File
|
1994-08-01
|
43KB
|
948 lines
The following excerpt hails from "Chapter 3" of the "IRIX 5.1 IDO
Release Notes," and is followed by "Appendix A" which is the
Dynamic Shared Objects--DSOs--Frequently Asked Questions list.
______________________________________________________________________________
"Dynamic Linking and DSOs"
In previous versions of IRIX (pre-5.0), executables were only "statically
linked". This means that all references must be resolved (and their
addresses fixed) at link time (by LD(1)). In this release, such
programs, although they might use pre-5.0 shared libraries (which are
referred to now as "static shared libraries") are referred to as "non-
shared". They are produced by compiling and linking with the
"-non_shared" option. The code so created is *not* position-independent
(PIC).
In 5.0 and later IRIX releases, in addition to being statically linked by
LD(1), programs are, by default, compiled as PIC code and "dynamically
linked", that is, part of the program may be relocated dynamically at run
time. There are two types of dynamically linked objects:
* The executable itself. This consists of your main program and
PIC code extracted from all archive libraries linked with it.
Code within the executable is not relocated at run time, but
some of its references will be. The executable is linked
"-call_shared".
* External sharable dynamically linked objects called "dynamic
shared objects" (DSOs), which are not part of the executable
itself. DSOs and their references may be dynamically relocated
at run time. DSOs are linked "-shared". DSOs by convention
have the extension ".so". A DSO may be shared by several users
and/or programs, possibly at different addresses.
You cannot mix "non-shared" objects and PIC objects in the same
executable.
On this and future release, "static shared libraries" are supported only
for the use of existing (pre-5.0) executables that reference them. You
can neither create new static shared libraries nor link new code with
existing static shared libraries.
PIC code satisfies references indirectly by using a Global Offset Table
(GOT), which allows code to be relocated simply by updating the GOT.
Your executable has one GOT, and each DSO it uses has one GOT.
When a dynamically linked executable is started, the run-time linker,
RLD(1), is invoked to prepare the program for execution. This
preparation involves:
* Filling in certain global values.
* Relocating any dynamic shared objects (DSOs) that your program
references.
* Resolving data symbols in DSOs that were unresolved at static
link time by LD(1).
With very few exceptions, all executable objects in this release are
dynamically linked. A new component, the run-time linker /lib/rld, and
all standard DSOs (file extension ".so") are necessary for programs to
execute.
More information about these types of objects appears in Appendix A,
"Frequently Asked Questions about DSOs," (include below) and in the
"IRIX Programming Guide".
"Object File Format Changes"
The compiler tools and the link editor now produce ELF format objects and
executables by default. DSO is supported only in ELF executables and
object files. COFF files are run on IRIX 5.0 with the IRIX 4.0.5 ABI,
and ELF files are run with the IRIX 5.0 ABI; hence, the linker refuses
to mix (pre-5.0) COFF and ELF objects.
Two new header files are associated with ELF objects:
/usr/include/elf_abi.h contains definitions that are generic to all
implementations. /usr/include/elf_mips.h contains definitions specific
to the MIPS architecture. See the "System V Application Binary
Interface" and "System V Application Binary Interface MIPS Processor
Supplement", published by UNIX System Laboratories, for details.
A new object file reader, ELFDUMP(1), is associated with ELF format
files. This program is known on some other SVR4-compliant systems as
"dump".
______________________________________________________________________________
=============================================
Frequently Asked Questions about DSOs
=============================================
This list hails from the IRIX 5.2 DSO man page, begins near the top of
page 5, and constitues the remaining 15+ pages of this manual page.
FREQUENTLY ASKED QUESTIONS
List of Questions:
1) What is DSO?
2) How do dynamic shared objects compare with shared libraries?
3) How do I maintain binary compatibility between versions of
dso's?"
4) Under which versions of the OS can I use DSO?
5) What object-file format does DSO use?
6) How do I install the tools so I can use DSO on my system?
7) How do I build an executable that uses a shared object?
8) How do I build an executable that doesn't use shared
linking?"
9) How do I tell if an executable will use dynamic linking?
10) How do I build a shared object?
11) Where does the system look for shared objects at runtime?
12) What is Quickstart?
13) What is the so_locations file?
14) What directives can be put in a so_locations file?
15) What is /usr/lib/so_locations?
16) If I don't have a valid so_locations, can I generate one from
all the .so's in, say, /usr/lib?"
17) How expensive is it (at runtime) to NOT use the
-update_registry option?"
18) How and when will Quickstart be used?
19) What about run-time loading under user control?
20) What benefits will I get from DSO?
21) What costs are associated with DSO?
22) What is the -KPIC option?
23) Must main programs which want to use DSO's use -KPIC for
compilation?"
24) How do I change my assembly language sources to use -KPIC?
25) Can I mix IRIX 4 static shared libraries with DSO's?
26) What options do I have when building a shared object?
27) What pitfalls should I know about which are associated with
DSO?"
Page 5 Release 5.2
DSO(5) Silicon Graphics DSO(5)
28) What should I do about a GOT overflow?
29) How are multiple versions of DSO's supported?
30) Where can I find more documentation on DSO?
1) What is DSO?
DSO stands for Dynamic Shared Objects. DSO provides a capability similar
to static shared libraries under Cypress and earlier versions of the
IRIX, e.g., it gives applications the ability to share the text of
heavily used libraries, which need not be included in the executable
file. However DSO has two important distinctions from static shared
objects.
2) How do dynamic shared objects compare with shared libraries?
First, a dynamic shared object contains only position-independent code,
so that it may be mapped into the virtual address space of different
processes at different addresses and still be shared. Second, dynamic
shared objects, and indeed the executable itself are mapped in by a
runtime loader, rld, which resides in memory in the same address space as
the executable. This gives the system the ability to change the binding
of symbols during executions, at the request of the executing program.
This capability should prove useful across a large segment of
applications.
3) How do I maintain binary compatibility between versions of dso's?
As long as the shared objects maintain the same exported symbols, or
perhaps add new symbols without removing any or changing semantics, and
don't change exported structures, they will be binary compatible.
Ordering of symbols, routines, are irrelevant, as global data, etc. We
are working on a system called Delta-C++ which should allow you to add to
exported classes without recompiling.
4) Under which versions of the OS can I use DSO?
DSO is available under IRIX versions 5.0 and later. Programs built with
DSO will not work on earlier version of IRIX.
5) Which object-file format does DSO use?
DSO uses the ELF object file format, as defined in the SVR4 ABI. ELF
objects cannot be run under IRIX 4.0.5 or earlier.
6) How do I install the tools so I can use DSO on my system?
IRIX 5.0 and later releases all support/use DSO's. In order to compile
and build shared objects you will need to have the Developer's option
installed.
7) How do I build an executable that uses a shared object?
cc myfile.c -lmine
This will link you with libmine.so and also with libc.so.1, if either are
available. If no libmine.so is available, but there is a libmine.a, the
libmine.a will be used along with libc.so.1, and you will still get
dynamic linking. If you wish to be explicit, add the -call_shared flag
to the cc line:
Page 6 Release 5.2
DSO(5) Silicon Graphics DSO(5)
cc -call_shared myfile.c -lmine
8) How do I build an executable that doesn't use shared linking?
Use the -non_shared flag:
cc -non_shared myfile.c -lmine
9) How do I tell if an executable will use dynamic linking?
elfdump -o shows you the ELF program header. This contains all the
information necessary for exec and rld to run the program/shared object.
Only a.outs which use dynamic linking will have a PHDR, INTERP, or
DYNAMIC entry.
Here's an example, and a more detailed description of this stuff.
% elfdump -o /bin/cat
***PROGRAM HEADER***
Type Offset Vaddr Paddr Filesz Memsz Align RWX
PHDR 0x00000034 0x00400034 0x00400034 0x000000c0 0x00000000 0x00000004 r--
INTERP 0x00000100 0x00400100 0x00400100 0x00000009 0x00000009 0x00000004 r--
REGINFO 0x00000110 0x00400110 0x00400110 0x00000018 0x00000018 0x00000004 r--
DYNAMIC 0x00000150 0x00400150 0x00400150 0x00000a70 0x00000a70 0x00000010 r--
LOAD 0x00000000 0x00400000 0x00400000 0x00003000 0x00003000 0x00001000 r-x
LOAD 0x00003000 0x10000000 0x10000000 0x00001000 0x00001290 0x00010000 rwx
Each line is an entry in the program header, and refers to a "segment" of
the file.
PHDR points to the program header itself within the file. Only
executables which use dynamic linking will have this field.
INTERP
points to a place in the file where the name of the interpreter
required for this program is to be found. For any ABI-conforming
object, this name will be "/usr/lib/libc.so.1".
REGINFO
points to a place in the file where information about register setup
can be found. Currently this mostly consists of the correct gp
value for this object.
DYNAMIC
points to the information in the file which is needed by rld to
execute it correctly. This information includes the liblist, a
symbol table, and other information.
LOAD points to segments that are to be mapped into the memory image.
Page 7 Release 5.2
DSO(5) Silicon Graphics DSO(5)
The columns give various information about each segment.
Offset
is the offset in the file to the beginning of the segment.
Vaddr
is the virtual address of the beginning of the segment in the memory
image of the file, ASSUMING that it was mapped as described in the
LOAD entries
Paddr
is the same as Vaddr in our implementation.
Filesz
is the size of the segment in the file.
Memsz
is the size of the segment in the memory image. When this is larger
it is assumed to be zero-filled.
Align
is the alignment required by this section. If an segment is to be
mapped somewhere into memory other than at Vaddr, the new address
must be congruent to Vaddr modulo the alignment. In the example
above, the first segment must always be loaded at a page boundary,
and the second must always be loaded at a 64K boundary.
RWX specifies the protections r(ead), w(rite), or x(ecute) for the
segment.
Programs which are linked -non_shared do not have a PHDR, INTERP, or
DYNAMIC section. Thus elfdump -o is a convenient method to determine if
a program is linked -non_shared or not.
10) How do I build a shared object?
To begin with, build a .o or .a which contains all the routines you want
to have in your .so (shared object). This can be done with cc -c and ar.
Then invoke ld with the -shared flag. Normally the extension .so is used
to designate shared objects.
Here is an example:
cc -c myobj.c
ld -shared myobj.o -o myobj.so
-or-
<build libmine.a the usual way.>
ld -shared -all libmine.a -o libmine.so
Page 8 Release 5.2
DSO(5) Silicon Graphics DSO(5)
The -all flag in the second example tells ld to include all the routines
in the library. This is necessary since there are no undefined
references (in a main, say) which is the usual way that ld knows to
include files from an archive.
11) Where does the system look for shared objects at runtime?
The search path for shared objects is acquired in the following order:
1) the path of the shared object if given in the liblist,
2) in any directories specified via the
-rpath flag when the executable was built
3) in any directory specified by the LD_LIBRARY_PATH environment
variable, if it is defined
4) in the directories in the default path
(/usr/lib:/lib:/lib/cc:/usr/lib/cc)
If the _RLD_ROOT environment variable is defined, then its value is
appended to the front of any path specified by -rpath and the default
path. _RLD_ROOT itself is also a colon(:) separated list.
See the rld(1) manpage for details.
12) What is Quickstart?
Quickstart is an optimization. Using the so_locations file, each shared
object is pre-relocated by ld, as if it had been loaded at the address in
the so_locations file. That way, if nothing unusual happens when we
start up the application, all the shared objects will map at their
Quickstart addresses, and rld will not need to do a relocation pass over
them.
If for some reason more than one shared object wishes to map the same
address, rld will move one of them to an unused address and perform a
relocation pass to fix up the address references.
If one or more of the shared objects linked against at static link time
has changed by the time the program executes, rld will need to do extra
work to ensure that symbols have been resolved to their proper value.
13) What is the so_locations file?
In the directory in which you build a shared object, after you've
actually built one, you will notice a file named so_locations.
It is a registry of shared objects. It maintains the default or
Quickstart addresses of a group of shared objects which are to cooperate
by not having their default location overlap with one another. It is
generated and updated by ld each time it builds a shared object.
Page 9 Release 5.2
DSO(5) Silicon Graphics DSO(5)
14) What directives can be put in an so_locations file?
Comment line
so_name [ :st = { .text | .data | $range } base_addr,padded_size : ] *
where
so_name full path name (or trailing component) of a
shared object
st string identifying start of the segment description
.text | .data segment types: text or data
$range limit the range of address that can be used
base_addr address where the segment starts
padded_size padded size of the segment
The following directives control the placement of new shared objects:
$text_align_size=<align> padding=<pad-size>
$data_align_size=<align> padding=<pad-size>
These two directives specify the alignment and padding
requirements for text and data segments respectively.
The size value in so location is calculated based on:
(section size + padding) aligned to the section align size
The align values for text and data as well as the padding
values must be aligned to a bucket size. If not, ld will
generate a warning message and align these values to bucket
size.
$start_address=<addr>
Specifies where to start looking for addresses to put shared
objects.
$data_after_text=[ 1 | 0 ]
Instructs the linker to place data immediately after the text
at specified text and data alignment requirements.
We set the data_after_text to 0 if the argument of this directive
is missing.
Also, when building a dso with the -check_registry or -update_registry
flag, and if there is already an entry corresponding to this dso in the
so_location file, the linker will try to assign the same addresses for
text and data. However, if the size of the dso changes and does not fit
in the specified location any more, the linker will search for another
spot that fits. If the optional $range comment is given, the linker will
only place the dso in the specified range of addresses. If there is not
enough room, an error will be given.
15) What is /usr/lib/so_locations?
This file represents the default layout for the system shared objects.
Developers who build shared objects may find it interesting to consult
this file, in order to avoid collisions between their shared objects and
system shared objects. This file is absolutely irrelevant to users who
merely run programs which use shared objects.
Page 10 Release 5.2
DSO(5) Silicon Graphics DSO(5)
There are two options which are relevant, -update_registry, and <file>
looks at <file> and builds the current .so at a location which doesn't
conflict with anything in the file (unless the current one is listed. -
check_registry does not write to <file>. -update_registry <file> will
consult <file> as with -check_registry, but will attempt to write an
entry for the .so being built into <file>. If <file> is not writable, -
update_registry turns into If <file> is not readable -check_registry and
-update_registry are ignored.
16) If I don't have a valid so_locations file, can I generate one from all
the .so's in, say, /usr/lib?
There is no convenient method to do so. There is no guarantee that all
the .so's in /usr/lib have been coordinated so that a consistent
so_locations file can be made from them. So it is better to get the one
that a particular release was made with.
17) How expensive is it (at runtime) NOT to use -update_registry option?
The costs are all startup costs. It is very difficult to say how much a
particular executable will suffer since it depends on which shared
objects the program uses and whether they have been Quickstarted for the
same address. When there is a conflict between two objects, one will be
moved, which means that all addresses referring to names in that object
need to be relocated.
18) How and when will Quickstart be used?
Normally, the linker will use Quickstart unless there are unresolved
symbols at static link time.
In every executable and every shared object is a list of objects which
were looked at at static link time -- when the object was made. This
list also contains timestamps and checksums for each of the objects.
Various levels of extra work are required if the timestamp or checksum
has changed in the library at run-time.
19) What about run-time loading under user control?
We support an interface known as libdl, which allows users to dynamically
load their own shared objects as needed. The calls are
dlopen() -- open a new shared object and get a "handle" to it.
dlsym() -- find the value of a name defined in an object.
dlclose()-- close a shared object.
dlerror()-- report errors.
sgidladd() -- functions much like dlopen however it exposes
all symbols to the rest of the program.
Consult the individual manpages for details.
Page 11 Release 5.2
DSO(5) Silicon Graphics DSO(5)
20) What benefits will I get from DSO?
Executables linked with shared objects will be smaller since the shared
objects are not part of the executable file image.
Executables which use a shared object need not be relinked if a shared
object is changed -- once the updated shared object is installed, the
executable will pick it up automatically.
Shared libraries are much easier to build, use, and debug than static
shared libraries.
DSO allows application designers to make more machine-independent
software. System-dependent routines can be given a uniform interface and
a shared object which implements that interface can be built for each
different platform. Then an actual application can be shipped as-is
("shrink-wrapped" software) to various platforms and run on them all.
DSO gives applications the ability to change the binding of symbols at
run time, under user control.
21) What costs are associated with DSO?
A shared object incurs two costs, both against performance.
At startup, there will be a startup cost while rld maps in the various
objects, performs symbol resolution, etc. We believe this cost is small
compared to the time it takes to contact the X server, for example.
Quickstart will reduce this time for smaller applications.
A shared object's text must be PIC (position independent code).
PICification is accomplished by the code generator (ugen) and assembler
(as), when the -KPIC flag is specified. This is the default However, PIC
code is necessarily slower. Experiments have indicated that this speed
reduction is usually less than 5 percent, but can be as much as 15
percent. depending on the application. PIC code seems to be worst on
very small leaf routines which access global data.
22) What is the -KPIC option?
This flags tells the code generator and assembler to generate PIC
directly. The result is an object file that can be put into a DSO
without further modification
cc -KPIC -c foo.c
will give you a PIC object foo.o. Other drivers (cc, pc, f77, and as)
also accept the -KPIC option. This is the default.
Routines written in assembly languages need to be modified before -KPIC
can be used. See the question below.
PIC objects generated by using -KPIC must be compiled -G 0.
Page 12 Release 5.2
DSO(5) Silicon Graphics DSO(5)
23) Must main programs which want to use DSO's use -KPIC for compilation?
Yes. DSO's use -KPIC so that position-independent code will be
generated. Main programs are not generally position-independent, but
must still use the DSO calling convention when calling a routine which is
defined in a DSO. In particular, this means that a main program must have
a GOT, and the code which is generated must use it. Therefore, modules
which will become part of main programs must be compiled -KPIC as well as
modules which become part of DSO's.
24) How do I change my assembly language sources to use -KPIC?
Several new assembler directives are added to support generation of PIC.
You should also get yourself familiar with the MIPS ABI Supplement and
the PIC coding model it describes. In addition, files which are to be
assembled with -KPIC must also be -G 0. This is normally turned on by
the driver by default.
Note that with the exception of (a) and (d), all other directives
described below will be ignored when -KPIC is not explicitly specified.
Also, item (d), ".gpword", will be turned into ".word". The result will
be a NON-PIC version of the same routine.
a) .option pic2
This directive forces the assembler to mark the output object file "PIC"
and activates the following directives. It overrides the command line
argument. Normally, you don't need to specify this directive. Instead,
you should use the -KPIC or -non_shared flags to toggle between
generating PIC or non-PIC.
Note that even though -KPIC will be made the default for the high-
language driver (cc/pc/f77) in future releases, it will *NOT* be the
default for assembly sources. You will always have to explicitly specify
-KPIC for compiling .s files.
b) .cpload reg
This directive expands into three instructions that sets the gp register
to the context pointer value for the current function. The three
instructions are:
lui gp,_gp_disp
addui gp,gp,_gp_disp
addu gp,gp,reg
_gp_disp is a reserved symbol defined by the linker to be the distance
between the lui instruction and the context pointer. This directive is
required at the beginning of each subroutine that uses the gp register.
You must add this directive at the beginning of every procedure, with the
exception of leaf-procedures that do not access any global variables, and
procedures that are static (i.e., not marked .globl or .extern).
Page 13 Release 5.2
DSO(5) Silicon Graphics DSO(5)
c) .cprestore offset
This directive causes the assembler to issue
sw gp,offset(sp)
at the point where it appears. Additionally, it causes the assembler to
emit
lw gp,offset(sp)
after every jump-and-link (jal) or branch-and-link (bal) operation,
thereby restoring the gp register after function calls. The programmer
is responsible for allocating the stack space for the gp. This space
should be in the saved register area of the stack frame to remain
consistent with MIPS' calling and debugger conventions.
d) .gpword local-sym
This directive is similar to .word except that the relocation entry for
local-sym has the R_MIPS_GPREL32 type. After linkage, this results in a
32-bit value that is the distance between local-sym and the context
pointer (i.e. the gp). local-sym must be local. It is currently used
for PIC switch tables.
e) .cpadd reg
This adds the value of the context pointer (gp) to reg.
EXAMPLES:
This is a simplified version of the "hello world" program:
--------------------------------------------------------------
.option pic2
.data
.align 2
$$5:
.ascii "hello world\X0A\X00"
.text
.align 2
main:
.set noreorder
.cpload $25
.set reorder
subu $sp, 40
sw $31, 36($sp)
.cprestore 32
la $4, $$5
jal printf
move $2, $0
lw $31, 36($sp)
addu $sp, 40
j $31
----------------------------------------------------------------
The actual instructions generated by the assembler will be:
lui gp,0 #
Page 14 Release 5.2
DSO(5) Silicon Graphics DSO(5)
addiu gp,gp,0 # generated by .cpload
addu gp,gp,t9 #
lw a0,0(gp) # gp-relative addressing used
lw t9,0(gp) # t9 is used for func. call
addiu sp,sp,-40
sw ra,36(sp)
sw gp,32(sp) # from .cprestore
jalr ra,t9 # jal is changed to jalr
addiu a0,a0,0
lw ra,36(sp)
lw gp,32(sp) # activated by .cprestore
move v0,zero
jr ra
addiu sp,sp,40
nop
----------------------------------------------------------------
NOTE:
The MIPS's ABI required register t9 ($25) be used for indirect function
call, so .cpload should always use $25. No reorder mode should also be
used. Also, programmers should make sure that t9 is dead before any
function call.
If your program uses an indirect jump (jalr), you must also use t9 as the
jump register.
If you have an unconditional jump to an external label:
j _cerror
you have to rewrite it into indirect jump via t9, i.e.:
la t9,_cerror
j t9
If you use branch-and-link (bal) instruction, and if the target procedure
begins with a .cpload, you have to specify an alternate entry point:
foo: .set noreorder # callee
.cpload $25
.set reorder
$$1: ... # alternative entry point
...
j $31 # foo returns
bar: ... # caller
...
bal $$1 # by-pass the .cpload
...
This is very important because .cpload assumes register $25 contains the
address of foo, but in this case $25 is not set up. Note that since both
foo and bar reside in the same file, they must have the same value for
$gp. So the .cpload instructions can be and must be bypassed. However,
Page 15 Release 5.2
DSO(5) Silicon Graphics DSO(5)
since foo can still be called from outside, the .cpload is still
required.
Alternatively, if you don't want to have an alternate entry point, you
can set up register $25 before the bal:
la t9,foo
bal foo
but this will be less efficient.
position-independent jump table (or any table of text addresses).
Entries of the address table created by .gpword are converted into
displacement from the context pointer. To get the correct text address,
.cpadd should be used to add the value of gp back to them. Since the gp
is updated by the run-time linker, the correct text address can be
reconstructed regardless of the location of the dso.
25) Can I mix IRIX 4 static shared libraries with DSO's?
We do not anticipate ever allowing an a.out to use both static shared
libraries and dso.
26) What options do I have when building a shared object?
If you specify the flag -B dynamic while linking a shared object, symbols
in the shared object will be resolved differently than the default
linkage convention. In particular, the runtime linker will always try to
resolve any symbols referenced in that object to symbols defined in that
object first, instead of looking for definitions in objects in the order
specified on the link line.
The effect of this is to make all symbols defined and used in such
objects non-preemptable. Ordinarily a such symbol definitions could be
preempted by a definition in an earlier shared object, but when -B
symbolic is specified, this is not the case.
27) What pitfalls are associated with DSO?
Behind most of the surprises that users will get is the fact that linking
semantics are fundamentally different, but only in a subtle way. Let us
suppose that your program links with three libraries, libA, libB and
libC, in that order. Further suppose that both libA and libC define some
symbol x, but don't use it. Furthermore, let us suppose that libB
contains a reference to x. Archive linking (the old way) will resolve
B's reference to x to the definition in C, whereas shared object linking
will resolve B's reference to x to the definition in A.
Why the difference? With archive linking, when libA is examined, there
is no outstanding reference to x, hence the definition of x is not
extracted from the archive. Later when libC is examined, there is a
reference to x, so it is loaded.
With shared objects, all the constituent object files have been joined
into one object, so all symbol definitions are always present. The
resolution rule is simple, take the definition in the object listed
Page 16 Release 5.2
DSO(5) Silicon Graphics DSO(5)
first. Thus the definition in libA is used.
Another sort of surprise is the "runtime dangling reference". It is
altogether possible to build and link an application with no errors or
even warnings, only to get a message from rld stating that your program
has unresolvable symbols.
What's going on? Well, if you build a shared object as part of your
program, the linker will not normally complain about undefined symbols
during a link of a shared object. This is because undefined symbols are
expected during such a build and are perfectly acceptable. But if the
main program does not use a symbol, it does not get flagged as undefined
during static linking. Thus the runtime "surprise". You can use the -
no_unresolved flag to the linker to avoid such surprises.
Now we get to a nasty pitfall which can be avoided by some cleverness in
building a shared object. If a particular object in an archive has an
external reference to a data symbol (which it expects to be defined in
main, libl.a, for example) the linker would not try to resolve that
external unless the object file in question was actually referenced by
the main program. Now if that archive is turned into a shared object
naively, the external data reference must be resolved whenever ANY
function in the shared object is used, even if no function in the object
file in question is ever called and no use is made of the external data
symbol in question.
This can lead to a scenario where a user has a link that worked with the
archives, but builds a program which gets nuked by the runtime linker
under the new scheme of things. I believe that it is a very bad idea for
us to convert libraries. such as libl.a, which contain external data
symbols, to shared objects naively.
One thing that can be done is to split the archive into several shared
objects which are placed on the liblist of a "master" shared object.
Since rld will not by default try to resolve data symbols until the first
call is made to a particular object we can create the situation where no
attempt to resolve the offending external data symbol is made until a
call is made to the object in which it is referenced.
Here's an example of how that works: Let us suppose that
has_extern_data.o is an object with an undefined external in it which
resides in the archive libxyz.a Here is how to isolate that external
data reference:
First make has_extern_data.o into a shared object all its own.
% ar x libxyz.a has_extern_data.o
% ld -shared has_extern_data.o -o has_extern_data.so
Now, make libxyz.so, excluding has_extern_data.o from being included
directly, but instead putting it in the liblist of libxyz.so
Page 17 Release 5.2
DSO(5) Silicon Graphics DSO(5)
% ld -shared -all -exclude has_extern_data.o libxyz.a has_extern_data.so -o libxyz.so
28) What should I do about a GOT overflow?
By default, addresses are loaded out of the Global Offset Table (GOT)
using a 16 bit offset from a context pointer. This means that the size
of the GOT is limited (by default) to 64K bytes, or about 16 K symbols.
When there are too many symbols referenced by a DSO (or a.out) the linker
issues the messag "GOT overflows" and will specify an object file which
references the symbol which is "out of reach".
SGI recommends that when developers encounter this problem, they attempt
to split the DSO or a.out in question into several smaller DSO's, each of
which can conform to the GOT size limit. Maximum performance can be
achieved this way.
However, as an alternative, developers may wish to use the -xgot
compile-time flag to tell the compiler to issue a different (and slower)
code sequence uses a 32-bit offset. This will allow the GOT to contain
up to 1G entries. However, it is critical that every object linked into
a final DSO or a.out be compiled with -xgot turned on, otherwise code may
have been generated which will not work with an extended GOT. However,
files compiled with -xgot may be linked into a DSO or a.out which has a
GOT that does not exceed the 16K limit and will work correctly, if
somewhat slower. The GOT size of any shared objects linked is
irrelevant.
The directory /usr/lib/xgot contains the extended-GOT versions of those
objects which SGI has built both normally and -xgot. If a system or third
party archive contains small GOT objects which are needed in an extended
GOT link, a developer can take the following steps: 1) Look in
/usr/lib/xgot to see if an extended GOT version exists. 2) Turn the
archive into its own shared object, thus isolating it from the extended
GOT binary. 3) contact the archive provider. In a few cases (crt1.o,
crtn.o, c++init.o, and fixade.o), where the performance issues were
minimal, the default objects in /usr/lib are in fact built large GOT.
29) How are multiple versions of DSO's supported?
IRIX 5.0.1 (Compilers v3.16) and later supports the ability to tag shared
objects and executables with a version number. This is intended to
support interface changes. Details are below; items marked (SGI ONLY) do
not apply to MSIG ABI binaries, but only to binaries generated on IRIX
without the -abi flag turned on.
Versioning of Shared Objects.
QUICK OVERVIEW
In order for a shared object to be versioned in the future
the following needs to be done:
* Version strings consist of 3 parts and a dot: The string "sgi",
a decimal number (the major number), a dot, and a decimal number
Page 18 Release 5.2
DSO(5) Silicon Graphics DSO(5)
(the minor number).
* Add the command -set_version sgi1.0 to the command to build
the shared object (cc -shared, ld -shared, etc.).
* (Future) Whenever you make a COMPATIBLE change update the minor version
number (the one after the dot), and add the latest version string
to colon-separated list of version strings, e.g., -set_version
sgi1.0:sgi1.1:sgi1.3
* (Future) Whenever you make an INCOMPATIBLE change, update the
major version number. Pass this as the version list, e.g.,
-set_version sgi2.0. Change the filename of the OLD shared object
by adding a dot followed by the previous major number to the filename
of the shared object. DO NOT CHANGE the soname of the object.
No change to the file contents are necessary or desirable. Simply
rename the file.
HOW IT ALL WORKS
* Versioning will only be available for NON-ABI executables.
The current ABI does not require objects to have versioning, nor
does it require systems to pay attention to versioning. It does
allow objects to contain version strings, but does not require
systems to do anything with this information.
* NON-ABI compliant executables will have a SGI_ONLY bit turned
on in the .dynamic section. This flag will be understood and
reported by elfdump. Only executables with this flag on will
get the versioning treatment described below. This flag will
be on by default.
* When an executable is linked against a shared object, the last
entry of the shared object's version string is recorded in the
executable as part of the liblist. This can be examined by
elfdump -Dl.
* When an executable is linked, the user may specify -require_minor or
-ignore_minor for each shared object linked against. If
-require_minor is specified, a bit will be set in the flags field of
the liblist entry for the shared object in question. The default
is -ignore_minor.
* When an executable (ABI or SGI_ONLY) is run rld will look
for the proper filename in its usual search routine.
* (SGI_ONLY) If a file with the correct name is found the
version string in the liblist is compared to the list
of version strings in the shared object. If the REQUIRE_MINOR bit
is set in the liblist entry, and there is an exact match between the
version string in the depender and one of the strings in the version
list of the dependee, then that library is used. If the
Page 19 Release 5.2
DSO(5) Silicon Graphics DSO(5)
REQUIRE_MINOR bit is clear, and if there is a match of major
versions, then that library is used.
* (SGI_ONLY) If no proper match is found, a new soname is built
by taking the soname found in the executables liblist, and the
major number found in the version string corresponding to that
liblist entry, and putting them together as <soname>.<major>
This is searched for in the same way as above. Version strings are
matched in exactly the same way as described above.
30) Where can I find more documentation on DSO?
Besides the other manpages mentioned below, System V Application Binary
Interface and System V Application Binary Interface -- are both good
sources of DSO implementation details.